home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
Games
/
net3d-0.08
/
brain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-22
|
16KB
|
612 lines
/* brain.c
*
* Contains functions for dealing with vehicle brains
*/
#include "net3d.h"
/* action and condtion function types.
*/
typedef Bool (*c_func)(struct vehicle *, struct vehicle **,
struct object **);
typedef void (*a_func)(struct vehicle *, struct vehicle **,
struct object **);
double objectdist(struct object *, struct object *);
struct object *objectahead(struct vehicle *, struct object *,
Bool (*)(struct object *));
/* interesting function prototypes.
*/
static Bool isthreat(struct object *);
static Bool istree(struct object *);
static Bool isany(struct object *);
static Bool isprize(struct object *);
/* action and condtion function prototypes.
*/
/* conditions */
static Bool hplow(struct vehicle *, struct vehicle **, struct object **);
static Bool ammolow(struct vehicle *, struct vehicle **, struct object **);
static Bool threatfar(struct vehicle *, struct vehicle **, struct object **);
static Bool treefar(struct vehicle *, struct vehicle **, struct object **);
static Bool anyfar(struct vehicle *, struct vehicle **, struct object **);
static Bool threatclose(struct vehicle *, struct vehicle **, struct object **);
static Bool treeclose(struct vehicle *, struct vehicle **, struct object **);
static Bool anyclose(struct vehicle *, struct vehicle **, struct object **);
static Bool underfire(struct vehicle *, struct vehicle **, struct object **);
static Bool reload(struct vehicle *, struct vehicle **, struct object **);
static Bool reslow(struct vehicle *, struct vehicle **, struct object **);
static Bool moving(struct vehicle *, struct vehicle **, struct object **);
static Bool stall(struct vehicle *, struct vehicle **, struct object **);
static Bool altlow(struct vehicle *, struct vehicle **, struct object **);
static Bool above(struct vehicle *, struct vehicle **, struct object **);
static Bool below(struct vehicle *, struct vehicle **, struct object **);
static Bool always(struct vehicle *, struct vehicle **, struct object **);
static Bool prizefar(struct vehicle *, struct vehicle **, struct object **);
static Bool prizeclose(struct vehicle *, struct vehicle **, struct object **);
static Bool maybe(struct vehicle *, struct vehicle **, struct object **);
static Bool counting(struct vehicle *, struct vehicle **, struct object **);
static Bool collision(struct vehicle *, struct vehicle **, struct object **);
/* actions */
static void noop(struct vehicle *, struct vehicle **, struct object **);
static void shoot(struct vehicle *, struct vehicle **, struct object **);
static void stop(struct vehicle *, struct vehicle **, struct object **);
static void accel(struct vehicle *, struct vehicle **, struct object **);
static void decel(struct vehicle *, struct vehicle **, struct object **);
static void left(struct vehicle *, struct vehicle **, struct object **);
static void right(struct vehicle *, struct vehicle **, struct object **);
static void climb(struct vehicle *, struct vehicle **, struct object **);
static void dive(struct vehicle *, struct vehicle **, struct object **);
static void detonate(struct vehicle *, struct vehicle **, struct object **);
static void wall(struct vehicle *, struct vehicle **, struct object **);
static void mine(struct vehicle *, struct vehicle **, struct object **);
static void gunsite(struct vehicle *, struct vehicle **, struct object **);
static void starttimer(struct vehicle *, struct vehicle **, struct object **);
static char *conditionnames[CONDITIONCOUNT] = { "hplow","ammolow","threatfar",
"treefar","anyfar",
"threatclose","treeclose",
"anyclose","underfire",
"reload","reslow","moving",
"stall","altlow","above",
"below","always","prizefar",
"prizeclose","maybe",
"counting","collision"};
static char *actionnames[ACTIONCOUNT] ={"noop","shoot","stop","accel",
"decel","left","right","climb",
"dive","detonate","wall","mine",
"gunsite","starttimer"};
static c_func conditionfuncs[CONDITIONCOUNT] = {
hplow,ammolow,threatfar,treefar,anyfar,
threatclose,treeclose,anyclose,
underfire,reload,reslow,moving,stall,
altlow,above,below,always,prizefar,
prizeclose,maybe,counting,collision,
};
static a_func actionfuncs[ACTIONCOUNT] = {
noop,shoot,stop,accel,decel,left,right,
climb,dive,detonate,wall,mine,gunsite,
starttimer,
};
/* readbrain - called by readfile() to parse a brain { } section
* for a vehicle.
*/
void readbrain(struct vehicle *nv, int fp)
{
char tok[256];
Bool donebrain = False;
while(!donebrain) {
ntoken(fp,tok);
if (!strcmp(tok,"state")) {
/* Read info about one state
*/
struct state *st;
int i;
Bool donestate = False;
if (nv->stcount > MAX_STATES_PER_VEHICLE)
fileerror("Maximum number of states exceeded","",fp);
st = &(nv->states[nv->stcount]);
/* Init state */
st->action = 0;
st->lcount = 0;
st->links = calloc(MAX_LINKS_PER_STATE,sizeof(struct link));
/* Read state number */
ntoken(fp,tok);
st->num = atoi(tok);
for(i=0; i<nv->stcount; i++)
if (nv->states[i].num == st->num)
fileerror("Duplicate state number",tok,fp);
nv->stcount++;
if (nv->currentstate == -1)
nv->currentstate = st->num;
/* Read curly bracket */
ntoken(fp,tok);
while(!donestate) {
ntoken(fp,tok);
if (!strcmp(tok,"action")) {
/* Read one action */
int ac;
ntoken(fp,tok);
for(ac=0; ac<ACTIONCOUNT; ac++)
if (!strcmp(actionnames[ac],tok))
break;
if (ac == ACTIONCOUNT)
fileerror("Action does not exist",
tok,fp);
st->action |= 1<<ac;
}
else if (!strcmp(tok,"link")) {
/* Read one state to state link */
struct link *lk;
lk = &(st->links[st->lcount]);
st->lcount++;
ntoken(fp,tok); /* read link info */
lk->st = atoi(tok);
lk->cond = 0;
lk->mask = 0;
ntoken(fp,tok); /* read { */
do {
int co;
char *cname;
/* Read a condition name, and check
* if it is a negative, and if it
* actually exists.
*/
ntoken(fp,tok);
if (tok[0] == '!')
cname = &tok[1];
else
cname = tok;
for(co=0; co<CONDITIONCOUNT; co++)
if (!strcmp(cname,
conditionnames[co]))
break;
if (co == CONDITIONCOUNT &&
strcmp(tok,"}"))
fileerror("Unknown condition",
tok,fp);
else if (co != CONDITIONCOUNT) {
lk->mask |= 1<<co;
if (tok[0] != '!')
lk->cond |= 1<<co;
}
} while(strcmp(tok,"}"));
}
else if (!strcmp(tok,"}")) {
donestate = True;
}
}
}
else if (!strcmp(tok,"}")) {
donebrain = True;
}
}
}
/* think - perform one state transition for this vehicle, based on it's
* state machine brain.
*/
void think(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct state *st = NULL;
int i;
int ln;
int ac;
/* find current state pointer.
*/
for(i=0; i<v->stcount; i++)
if (v->states[i].num == v->currentstate) {
st = &(v->states[i]);
break;
}
if (!st) {
printf("vehicle %s is in non-existant state %d!\n",v->code,
v->currentstate);
printf("resetting to dumb mode\n");
v->currentstate = -1;
return;
}
/* perform actions for this state.
*/
for(ac=0; ac < ACTIONCOUNT; ac++)
if (st->action & (1<<ac)) {
actionfuncs[ac](v,vh,oh);
}
/* evaluate all links.
* Algorithm - for each set bit in the mask, set the corresponding bit in
* the truemask if that condition is true. Then xor the truemask with
* the conditions, and if the result is zero (all same), take the link.
*/
for(ln=0; ln < st->lcount; ln++) {
struct link *lk;
int j;
long truemask = 0;
lk = &(st->links[ln]);
for(j=0; j<CONDITIONCOUNT; j++)
if ((lk->mask & (1<<j)) && conditionfuncs[j](v,vh,oh))
truemask |= (1<<j);
if ((truemask ^ lk->cond) == 0) {
v->currentstate = lk->st;
/* printf("changing to state %d\n",lk->st); */
break;
}
}
/* Reset the bumped flag.
*/
v->bumped = False;
}
/* objectahead - returns a pointer to the closest object ahead of v, within
* a 5 degree arc either side of v's current facing. Returns NULL if no
* object can be found.
*
* v - vehicle doing the looking
* oh - head of the object list
* interesting - function to determine if an object should condsidered
*/
struct object *objectahead(struct vehicle *v, struct object *oh,
Bool (*interesting)(struct object *))
{
double mindist = VIEW_RANGE*VIEW_RANGE*2;
struct object *closest = NULL;
struct object *part0;
double dist;
part0 = v->parts[0];
while(oh) {
/* only consider objects closer than the current closest,
* that are not part of the vehicle doing the looking, and
* that are judged relevant by the interesting() function.
*/
if ((dist = objectdist(part0,oh)) < mindist &&
interesting(oh) && oh->parent != v) {
double ang; /* angle to target */
double vang; /* heading */
double x,y;
/* compute angle to this object.
*/
x = oh->pos.y - part0->pos.y;
y = oh->pos.x - part0->pos.x;
ang = atan2(y,x);
/* compute sensible vehicle heading */
vang = v->angle;
vang = dtor(90.0) - vang;
while(vang < -PI)
vang += 2*PI;
while(vang > PI)
vang -= 2*PI;
/*
printf("heading=%f angle=%f xoff=%f yoff=%f\n",
rtod(vang),rtod(ang),x,y);
*/
if (dabs(ang - vang) < dtor(5.0)) {
closest = oh;
mindist = dist;
}
}
oh = oh->next;
}
/* If a vehicle is found, record it's vid for subsequent above/below/shoot
* actions.
*/
if (closest && closest->parent)
v->lastvid = closest->parent->vid;
else
v->lastvid = -1;
return closest;
}
/* objectdist - returns the distance^2 between two objects in the x/y
* plane.
*/
double objectdist(struct object *ob1, struct object *ob2)
{
double xd, yd;
xd = ob1->pos.x - ob2->pos.x;
yd = ob1->pos.y - ob2->pos.y;
return xd*xd + yd*yd;
}
/*************************************************************************
* Condition functions
*/
static Bool hplow(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return (v->hp < 5);
}
static Bool ammolow(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return (v->ammo < 5);
}
static Bool threatfar(struct vehicle *v, struct vehicle **vh,
struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,isthreat);
return cst != NULL;
}
static Bool treefar(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,istree);
return cst != NULL;
}
static Bool anyfar(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,isany);
return cst != NULL;
}
static Bool threatclose(struct vehicle *v, struct vehicle **vh,
struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,isthreat);
return cst && vehicledist(v,cst->parent) < 40*40;
}
static Bool treeclose(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,istree);
return cst && vehicledist(v,cst->parent) < 40*40;
}
static Bool anyclose(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,isany);
return v->bumped || (cst && objectdist(v->parts[0],cst) < 40*40);
}
static Bool underfire(struct vehicle *v, struct vehicle **vh,
struct object **oh)
{
return v->lasthit >= 0.0 && v->lasthit < 3.0;
}
static Bool reload(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return v->reload > 0;
}
static Bool reslow(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return v->res < 5;
}
static Bool moving(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return dabs(v->velocity) > 1.0;
}
static Bool stall(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return v->velocity < 5.0;
}
static Bool altlow(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return v->parts[0]->pos.z < 10;
}
static Bool above(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct vehicle *tar;
tar = findbyvid(*vh,v->lastvid);
return tar && v->parts[0]->pos.z > tar->parts[0]->pos.z;
}
static Bool below(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct vehicle *tar;
tar = findbyvid(*vh,v->lastvid);
return tar && v->parts[0]->pos.z < tar->parts[0]->pos.z;
}
static Bool always(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return True;
}
static Bool prizefar(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,isprize);
return cst != NULL;
}
static Bool prizeclose(struct vehicle *v, struct vehicle **vh,
struct object **oh)
{
struct object *cst;
cst = objectahead(v,*oh,isprize);
return cst && vehicledist(v,cst->parent) < 40*40;
}
static Bool maybe(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return rand()%2 == 0;
}
static Bool counting(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
return v->ftimer > 0.0;
}
static Bool collision(struct vehicle *v, struct vehicle **vh,
struct object **oh)
{
return v->bumped;
}
/************************************************************************
* action functions
*/
static void noop(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
}
static void shoot(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
double turret_ang = 0.0;
struct vehicle *tar;
/* Fire only if there is a vehicle in sight, that still exists and
* that is within the elevation range of the firer's gun.
*/
if (v->lastvid != -1 && (tar = findbyvid(*vh,v->lastvid))) {
turret_ang = atan2(heightdiff(tar,v),sqrt(vehicledist(tar,v)));
if (dabs(turret_ang) < v->max.turret_ang) {
/* printf("firing at %s\n",tar->code); */
fire(vh,oh,v);
}
}
}
static void stop(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
v->angle_vel = 0;
v->velocity = 0;
v->climb = 0;
}
static void accel(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
if (v->velocity < v->max.velocity)
v->velocity += DELTA_VELOCITY;
}
static void decel(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
if (v->velocity > -(v->max.velocity))
v->velocity -= DELTA_VELOCITY;
}
static void left(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
rotatevehicle(v,v->angle - dtor(5.0));
}
static void right(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
rotatevehicle(v,v->angle + dtor(5.0));
}
static void climb(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
}
static void dive(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
}
static void detonate(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
v->hp = -1;
}
static void wall(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
}
static void mine(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
}
static void gunsite(struct vehicle *v, struct vehicle **vh, struct object **oh)
{
}
static void starttimer(struct vehicle *v, struct vehicle **vh,
struct object **oh)
{
v->ftimer += 5.0;
}
/* example brain for gunsite
brain {
state 1 {
action left
link 2 { threatfar }
}
state 2 {
action fire
action something
link 1 { !threatfar }
}
}
*/
static Bool isthreat(struct object *o)
{
return o->parent && (o->parent->owner == o_player ||
o->parent->owner == o_network || o->parent->type == t_gunsite);
}
static Bool istree(struct object *o)
{
return o->parent && o->parent->type == t_tree;
}
static Bool isany(struct object *o)
{
return !o->parent || !(o->parent->type == t_scenery ||
o->parent->type == t_bullet || o->parent->type == t_missile ||
o->parent->type == t_shrapnel);
}
static Bool isprize(struct object *o)
{
return o->parent && (o->parent->type == t_weapon ||
o->parent->type == t_munitions);
}